using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Text;
using System.Windows.Forms;

using Derm.Render;

namespace ShaderGen.Ui
{
	public partial class ShaderEditorControl : UserControl
	{
		#region Constructors

		public ShaderEditorControl(string shaderPath)
		{
			InitializeComponent();

			// Text box fills control
			mShaderTextBox.Dock = DockStyle.Fill;
			// Load text
			mShaderTextBox.Load(shaderPath);
			// Include text editor
			EditorContainer.Controls.Add(mShaderTextBox);

			// Preprocessor symbol combo box initialization
			UpdatePreprocessorSymbolComboBox();
		}

		/// <summary>
		/// The text editor control.
		/// </summary>
		private readonly ShaderTextBox mShaderTextBox = new ShaderTextBox();

		#endregion

		#region Preprocessor Symbol Selection

		private class PreprocessorSymbol
		{
			public PreprocessorSymbol(string symbol)
			{
				// Store symbol
				Symbol = symbol;
				// Initialize check box
				CheckControl.Text = Symbol;
				CheckControl.CheckState = CheckState.Unchecked;
			}

			/// <summary>
			/// Control used for rendering ComboBox item.
			/// </summary>
			public readonly CheckBox CheckControl = new CheckBox();

			/// <summary>
			/// The preprocessor symbol.
			/// </summary>
			public readonly string Symbol;
		}

		private void UpdatePreprocessorSymbolComboBox()
		{
			List<string> preprocessorSymbols = ShaderSourcePreprocessor.Parse(mShaderTextBox.Text);
			
			// Empty combo box
			CmbPreprocessorSymbols.Items.Clear();

			// Default-reset special item
			PreprocessorSymbol undefinedSymbolsItem = new PreprocessorSymbol("Undefined set");
			undefinedSymbolsItem.CheckControl.CheckState = CheckState.Checked;
			CmbPreprocessorSymbols.Items.Add(undefinedSymbolsItem);

			if (preprocessorSymbols.Count > 0) {
				// Populate combo box
				foreach (string symbol in preprocessorSymbols) {
					PreprocessorSymbol item = new PreprocessorSymbol(symbol);

					CmbPreprocessorSymbols.Items.Add(item);
				}
			} else {
				// No preprocessor symbols
				CmbPreprocessorSymbols.Enabled = false;
			}
			mShaderTextBox.HighlightSyntax();
		}

		private void CmbPreprocessorSymbols_DrawItem(object sender, DrawItemEventArgs e)
		{
			ComboBox comboBox = (ComboBox) sender;

			e.DrawBackground();

			if ((e.State & DrawItemState.ComboBoxEdit) != 0) {
				StringBuilder sb = new StringBuilder();
				uint symbolCount = 0;

				for (int i = 1; i < comboBox.Items.Count; i++) {
					PreprocessorSymbol preprocessorSymbol = (PreprocessorSymbol) comboBox.Items[i];

					if (preprocessorSymbol.CheckControl.CheckState == CheckState.Checked) {
						sb.AppendFormat("{0}+", preprocessorSymbol.Symbol);
						symbolCount++;
					}
				}
				if (symbolCount > 0) {
					sb.Remove(sb.Length - 1, 1);

					if (symbolCount == 1)
						e.Graphics.DrawString(sb.ToString(), e.Font, SystemBrushes.ControlText, e.Bounds.Left, e.Bounds.Top);
					else
						e.Graphics.DrawString("Multiple symbols", e.Font, SystemBrushes.ControlText, e.Bounds.Left, e.Bounds.Top);
				} else {
					PreprocessorSymbol undefinedSymbolsItem = (PreprocessorSymbol) comboBox.Items[0];

					if (undefinedSymbolsItem.CheckControl.CheckState == CheckState.Checked)
						e.Graphics.DrawString("Undefined set", e.Font, SystemBrushes.ControlText, e.Bounds.Left, e.Bounds.Top);
					else
						e.Graphics.DrawString("No symbol defined", e.Font, SystemBrushes.ControlText, e.Bounds.Left, e.Bounds.Top);
				}
			} else if (e.Index >= 0) {
				Bitmap controlBitmap = new Bitmap(e.Bounds.Width, e.Bounds.Height, e.Graphics);
				PreprocessorSymbol preprocessorSymbol = (PreprocessorSymbol) comboBox.Items[e.Index];

				// Update control esthetic
				preprocessorSymbol.CheckControl.BackColor = comboBox.BackColor;
				preprocessorSymbol.CheckControl.Bounds = e.Bounds;
				preprocessorSymbol.CheckControl.Font = e.Font;

				// Swap from control to combo box thru bitmap
				preprocessorSymbol.CheckControl.DrawToBitmap(controlBitmap, new Rectangle(0, 0, e.Bounds.Width, e.Bounds.Height));
				e.Graphics.DrawImage(controlBitmap, e.Bounds.X, e.Bounds.Y);
			}
		}

		private void CmbPreprocessorSymbols_SelectedIndexChanged(object sender, EventArgs e)
		{
			ComboBox comboBox = (ComboBox) sender;

			// No real selection
			if (comboBox.SelectedIndex < 0)
				return;

			PreprocessorSymbol symbolItem = (PreprocessorSymbol) comboBox.Items[comboBox.SelectedIndex];

			// Toggle item check state
			if (symbolItem.CheckControl.CheckState == CheckState.Checked)
				symbolItem.CheckControl.CheckState = CheckState.Unchecked;
			else
				symbolItem.CheckControl.CheckState = CheckState.Checked;

			if (comboBox.SelectedIndex != 0) {
				PreprocessorSymbol undefinedSymbolsItem = (PreprocessorSymbol) comboBox.Items[0];

				// Update shader text editor compiler context
				if (symbolItem.CheckControl.CheckState == CheckState.Checked)
					mShaderTextBox.CurrentCompilerContext.DefineSymbol(symbolItem.Symbol);
				else
					mShaderTextBox.CurrentCompilerContext.RemoveSymbol(symbolItem.Symbol);

				for (int i = 1; i < comboBox.Items.Count; i++) {
					PreprocessorSymbol comboItem = (PreprocessorSymbol) comboBox.Items[i];
					
					if (comboItem.CheckControl.CheckState == CheckState.Checked) {
						undefinedSymbolsItem.CheckControl.CheckState = CheckState.Unchecked;
						break;
					}
				}

				mShaderTextBox.GrayoutInactiveCode = true;
			} else {
				// Undefine all preprocessor symbols
				if (symbolItem.CheckControl.CheckState == CheckState.Checked) {
					for (int i = 1; i < comboBox.Items.Count; i++) {
						PreprocessorSymbol comboItem = (PreprocessorSymbol) comboBox.Items[i];

						comboItem.CheckControl.CheckState = CheckState.Unchecked;
					}
					mShaderTextBox.CurrentCompilerContext.RemoveSymbols();
				}

				mShaderTextBox.GrayoutInactiveCode = symbolItem.CheckControl.CheckState != CheckState.Checked;
			}

			comboBox.SelectedIndex = -1;	

			mShaderTextBox.HighlightSyntax();
		}

		#endregion


	}
}
